import random

from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from web import models
from django.conf import settings
from utils.tencent import sms
from utils import encrypt
from django_redis import get_redis_connection
from .bootstrap import BootStrapForm


# Create your views here.
class RegisterModelForm(BootStrapForm, forms.ModelForm):
    mobile_phone = forms.CharField(label="手机号码",
                                   validators=[RegexValidator(r"^(1[3|4|5|6|7|8|9])\d{9}$", "手机号码格式错误"), ])
    password = forms.CharField(label="密码", min_length=6, max_length=16, error_messages={
        'min_length': "密码长度不能小于6个字符",
        'max_length': "密码长度不能大于16个字符",
    }, widget=forms.PasswordInput())

    confirm_password = forms.CharField(label="确认密码", min_length=6, max_length=16, error_messages={
        'min_length': "密码长度不能小于6个字符",
        'max_length': "密码长度不能大于16个字符",
    }, widget=forms.PasswordInput())
    code = forms.CharField(label="验证码", min_length=4, max_length=4, error_messages={
        'min_length': "验证码长度为4个字符",
        'max_length': "验证码长度为4个字符"
    })

    class Meta:
        model = models.UserInfo
        # fields = '__all__'
        fields = ['email', 'username', 'password', 'confirm_password', 'mobile_phone', 'code']

    def clean_username(self):
        """
        邮箱钩子处理
        :return:
        """
        username = self.cleaned_data['username']
        # 判断用户名是否已存在
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已存在')
        return username

    def clean_email(self):
        """
        用户名钩子处理
        :return:
        """
        email = self.cleaned_data['email']
        # 判断邮箱是否已被使用
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已被使用')
        return email

    def clean_password(self):
        """
        密码钩子处理，对密码进行加密
        :return:
        """
        password = self.cleaned_data['password']
        return encrypt.md5(password)

    def clean_confirm_password(self):
        """
        确认密码钩子处理
        :return:
        """
        password = self.cleaned_data.get('password')
        confirm_password = encrypt.md5(self.cleaned_data['confirm_password'])
        if password != confirm_password:
            raise ValidationError("两次密码不一致")
        return confirm_password

    def clean_mobile_phone(self):
        """
        手机号码钩子处理
        :return:
        """
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号码已被使用')
        return mobile_phone

    def clean_code(self):
        """
        验证码钩子处理
        :return:
        """
        code = self.cleaned_data['code']
        mobile_phone = self.cleaned_data.get('mobile_phone')
        if not mobile_phone:
            return code

        # 通过手机号获取redis中保存的验证码
        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)

        # 如果redis中没有验证码
        if not redis_code:
            raise ValidationError("验证码失效或未发送，请重新发送")
        redis_str_code = redis_code.decode('utf-8')

        # 如果输入的验证码和redis中的验证码对不上
        if code.strip() != redis_str_code:
            raise ValidationError("验证码错误请重新输入")

        return code


class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label='手机号码',
                                   validators=[RegexValidator(r"^(1[3|4|5|6|7|8|9])\d{9}$", "手机号码格式错误"), ])
    tpl = forms.CharField()

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """
        手机号码校验钩子
        :return:
        """
        mobile_phone = self.cleaned_data['mobile_phone']

        # 判断短信模板是否有问题
        tpl = self.request.GET.get('tpl')
        template_id = settings.TENCENT_SMS_TRMPLATE[tpl]
        if not template_id:
            raise ValidationError('短信模板错误')
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if tpl == 'register':
            # 校验数据库中是否已有手机号码
            if exists:
                raise ValidationError('手机号码已存在')
        elif tpl == 'login':
            if not exists:
                raise ValidationError('手机号码不存在')
        else:
            raise ValidationError('发生了一些意外')

            # 发短信
        code = random.randrange(1000, 9999)
        print(code)  # 调试的时候使用
        sms_res = sms.send_sms_single(mobile_phone, template_id, [code])
        if sms_res['result'] != 0:
            raise ValidationError(f"短信发送失败，{sms_res['errmsg']}")

        # 验证码写入redis {django-redis组件}
        # 获取一个redis连接
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)

        return mobile_phone


class LoginSmsForm(BootStrapForm, forms.Form):
    mobile_phone = forms.CharField(label="手机号码",
                                   validators=[RegexValidator(r"^(1[3|4|5|6|7|8|9])\d{9}$", "手机号码格式错误"), ])
    code = forms.CharField(label="验证码", min_length=4, max_length=4, error_messages={
        'min_length': "验证码长度为4个字符",
        'max_length': "验证码长度为4个字符"
    })

    def clean_mobile_phone(self):
        """
        手机号码钩子处理
        :return:
        """
        mobile_phone = self.cleaned_data['mobile_phone']
        user_obj = models.UserInfo.objects.filter(mobile_phone=mobile_phone).first()
        if not user_obj:
            raise ValidationError('手机号码不存在')
        return user_obj

    def clean_code(self):
        """
        验证码钩子处理
        :return:
        """
        code = self.cleaned_data['code']
        mobile_phone = self.cleaned_data.get('mobile_phone')
        if not mobile_phone:
            self.add_error('手机号码不存在')
            return code

        # 通过手机号获取redis中保存的验证码
        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone.mobile_phone)

        # 如果redis中没有验证码
        if not redis_code:
            raise ValidationError("验证码失效或未发送，请重新发送")
        redis_str_code = redis_code.decode('utf-8')

        # 如果输入的验证码和redis中的验证码对不上
        if code.strip() != redis_str_code:
            raise ValidationError("验证码错误请重新输入")

        return code


class LoginForm(BootStrapForm, forms.Form):
    username = forms.CharField(label='邮箱或手机号码')
    password = forms.CharField(label="密码", min_length=6, max_length=16, error_messages={
        'min_length': "密码长度不能小于6个字符",
        'max_length': "密码长度不能大于16个字符",
    }, widget=forms.PasswordInput(render_value=True))  # render_value=True 表示输入错误时，默认值不清空
    code = forms.CharField(label="图片验证码")

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        password = self.cleaned_data['password']
        return encrypt.md5(password)

    def clean_code(self):
        """
        钩子，校验输入的图片验证是否正确
        :return:
        """
        code = self.cleaned_data['code']

        # 读取用户session中的图片验证码
        session_img_code = self.request.session.get('img_code')
        if not session_img_code:
            raise ValidationError("验证码已过期，请重新获取！！！")

        if code.upper().strip() != session_img_code.upper().strip():
            raise ValidationError("验证码输入错误！！！")

        return code


class UpdatePasswordForm(BootStrapForm, forms.Form):
    old_password = forms.CharField(label="原密码", min_length=6, max_length=16, error_messages={
        'min_length': "密码长度不能小于6个字符",
        'max_length': "密码长度不能大于16个字符",
    }, widget=forms.PasswordInput(render_value=True))
    new_password = forms.CharField(label="新密码", min_length=6, max_length=16, error_messages={
        'min_length': "密码长度不能小于6个字符",
        'max_length': "密码长度不能大于16个字符",
    }, widget=forms.PasswordInput(render_value=True))

    confirm_new_password = forms.CharField(label="重复新密码", min_length=6, max_length=16, error_messages={
        'min_length': "密码长度不能小于6个字符",
        'max_length': "密码长度不能大于16个字符",
    }, widget=forms.PasswordInput(render_value=True))

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_old_password(self):
        old_password = encrypt.md5(self.cleaned_data['old_password'])
        password = self.request.tracer.password
        if old_password != password:
            raise ValidationError('原密码输入错误！！！')
        return old_password

    def clean_new_password(self):
        new_password = self.cleaned_data['new_password']
        return encrypt.md5(new_password)

    def clean_confirm_new_password(self):
        new_password = self.cleaned_data['new_password']
        confirm_new_password = encrypt.md5(self.cleaned_data['confirm_new_password'])
        if new_password != confirm_new_password:
            raise ValidationError('两次密码不相等！！！')
        return confirm_new_password


class PersonalCenterModelForm(BootStrapForm, forms.ModelForm):
    email = forms.EmailField(label="邮箱", disabled=True)
    username = forms.CharField(label="用户名", disabled=True)
    mobile_phone = forms.CharField(label="手机号码", disabled=True)
    # project_num = forms.IntegerField(label="创建项目数", widget=forms.TextInput(attrs={"readonly": "readonly"}))
    project_num = forms.IntegerField(label="创建项目数", disabled=True)

    class Meta:
        model = models.UserInfo
        # fields = '__all__'
        fields = ['email', 'username',  'mobile_phone', 'project_num']
        # widgets = {
        #     'email': forms.Widget(attrs={"readonly": "readonly"}),
        # }
